package com.alan.springbootbase.dao;

import com.alan.springbootbase.entity.User;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.Map;

/**
 * @author Alan
 * @Description
 * @date 2021年02月03日 16:20
 */
@Repository
public interface UserRepository extends JpaRepository<User, Integer> {


    /**
     * 预先生成方法
     *  userRepository.findAll();
     * 	userRepository.findOne(1l);
     * 	userRepository.save(user);
     * 	userRepository.delete(user);
     * 	userRepository.count();
     * 	userRepository.exists(1l);
     * 	// ...
     */

    /**
     * 自定义简单查询
     * 自定义的简单查询就是根据方法名来自动生成 SQL，主要的语法是findXXBy,readAXXBy,queryXXBy,countXXBy, getXXBy后面跟属性名称：
     * User findByUserName(String userName);
     *
     * 也使用一些加一些关键字And 、 Or
     * User findByUserNameOrEmail(String username, String email);
     *
     * 修改、删除、统计也是类似语法
     * Long deleteById(Long id);
     * Long countByUserName(String userName)
     *
     * 基本上 SQL 体系中的关键词都可以使用，例如： LIKE 、 IgnoreCase、 OrderBy。
     * List<User> findByEmailLike(String email);
     * User findByUserNameIgnoreCase(String userName);
     * List<User> findByUserNameOrderByEmailDesc(String email);
     *
     * Keyword	Sample	JPQL snippet
     * And	findByLastnameAndFirstname	… where x.lastname = ?1 and x.firstname = ?2
     * Or	findByLastnameOrFirstname	… where x.lastname = ?1 or x.firstname = ?2
     * Is,Equals	findByFirstnameIs,findByFirstnameEquals	… where x.firstname = ?1
     * Between	findByStartDateBetween	… where x.startDate between ?1 and ?2
     * LessThan	findByAgeLessThan	… where x.age < ?1
     * LessThanEqual	findByAgeLessThanEqual	… where x.age ⇐ ?1
     * GreaterThan	findByAgeGreaterThan	… where x.age > ?1
     * GreaterThanEqual	findByAgeGreaterThanEqual	… where x.age >= ?1
     * After	findByStartDateAfter	… where x.startDate > ?1
     * Before	findByStartDateBefore	… where x.startDate < ?1
     * IsNull	findByAgeIsNull	… where x.age is null
     * IsNotNull,NotNull	findByAge(Is)NotNull	… where x.age not null
     * Like	findByFirstnameLike	… where x.firstname like ?1
     * NotLike	findByFirstnameNotLike	… where x.firstname not like ?1
     * StartingWith	findByFirstnameStartingWith	… where x.firstname like ?1 (parameter bound with appended %)
     * EndingWith	findByFirstnameEndingWith	… where x.firstname like ?1 (parameter bound with prepended %)
     * Containing	findByFirstnameContaining	… where x.firstname like ?1 (parameter bound wrapped in %)
     * OrderBy	findByAgeOrderByLastnameDesc	… where x.age = ?1 order by x.lastname desc
     * Not	findByLastnameNot	… where x.lastname <> ?1
     * In	findByAgeIn(Collection ages)	… where x.age in ?1
     * NotIn	findByAgeNotIn(Collection age)	… where x.age not in ?1
     * TRUE	findByActiveTrue()	… where x.active = true
     * FALSE	findByActiveFalse()	… where x.active = false
     * IgnoreCase	findByFirstnameIgnoreCase	… where UPPER(x.firstame) = UPPER(?1)
     */

    User findByUserName(String userName);
    User findByUserNameOrEmail(String username, String email);

    /**
     * 复杂查询
     * 在实际的开发中我们需要用到分页、删选、连表等查询的时候就需要特殊的方法或者自定义 SQL
     *
     * 分页查询
     * 分页查询在实际使用中非常普遍了，Spring Boot Jpa 已经帮我们实现了分页的功能，在查询的方法中，需要传入参数Pageable ,当查询中有多个参数的时候Pageable建议做为最后一个参数传入.
     *
     * Page<User> findALL(Pageable pageable);
     * Page<User> findByUserName(String userName,Pageable pageable);
     * Pageable 是 Spring 封装的分页实现类，使用的时候需要传入页数、每页条数和排序规则
     *
     * @Test
     * public void testPageQuery() throws Exception {
     * 	int page=1,size=10;
     * 	Sort sort = new Sort(Direction.DESC, "id");
     *     Pageable pageable = new PageRequest(page, size, sort);
     *     userRepository.findALL(pageable);
     *     userRepository.findByUserName("testName", pageable);
     * }
     * 限制查询
     *
     * 有时候我们只需要查询前N个元素，或者支取前一个实体。
     *
     * User findFirstByOrderByLastnameAsc();
     * User findTopByOrderByAgeDesc();
     * Page<User> queryFirst10ByLastname(String lastname, Pageable pageable);
     * List<User> findFirst10ByLastname(String lastname, Sort sort);
     * List<User> findTop10ByLastname(String lastname, Pageable pageable);
     */

    @Override
    Page<User> findAll(Pageable pageable);

    /**
     * 查找相应状态的角色
     * @param sort 排序对象
     * @param state 数据状态
     * @return 角色列表
     */
    List<User> findAllByState(Sort sort, String state);

    /**
     *自定义SQL查询
     * 其实 Spring Data 觉大部分的 SQL 都可以根据方法名定义的方式来实现，但是由于某些原因我们想使用自定义的 SQL 来查询，Spring Data 也是完美支持的；在 SQL 的查询方法上面使用@Query注解，如涉及到删除和修改在需要加上@Modifying.也可以根据需要添加 @Transactional对事物的支持，查询超时的设置等。
     *
     * @Modifying
     * @Query("update User u set u.userName = ?1 where u.id = ?2")
     * int modifyByIdAndUserId(String  userName, Long id);
     *
     * @Transactional
     * @Modifying
     * @Query("delete from User where id = ?1")
     * void deleteByUserId(Long id);
     *
     * @Transactional(timeout = 10)
     * @Query("select u from User u where u.emailAddress = ?1")
     * User findByEmailAddress(String emailAddress);
     *
     */

    @Query("select u from User u where u.userName like %?1%")
    List<User>findLikeUserName(String userName);

    @Query("select u from User u where u.userName like %?1%")
    List<Map<String,Object>> findLikeUserName1(String userName);

    /**
     *多表查询
     * 多表查询 Spring Boot Jpa 中有两种实现方式，第一种是利用 Hibernate 的级联查询来实现，第二种是创建一个结果集的接口来接收连表查询后的结果，这里主要第二种方式。
     *
     * 首先需要定义一个结果集的接口类。
     *
     * public interface HotelSummary {
     *
     * 	City getCity();
     *
     * 	String getName();
     *
     * 	Double getAverageRating();
     *
     * 	default Integer getAverageRatingRounded() {
     * 		return getAverageRating() == null ? null : (int) Math.round(getAverageRating());
     *        }
     *
     * }
     * 查询的方法返回类型设置为新创建的接口
     *
     * @Query("select h.city as city, h.name as name, avg(r.rating) as averageRating "
     * 		- "from Hotel h left outer join h.reviews r where h.city = ?1 group by h")
     * Page<HotelSummary> findByCity(City city, Pageable pageable);
     *
     * @Query("select h.name as name, avg(r.rating) as averageRating "
     * 		- "from Hotel h left outer join h.reviews r  group by h")
     * Page<HotelSummary> findByCity(Pageable pageable);
     * 使用
     *
     * Page<HotelSummary> hotels = this.hotelRepository.findByCity(new PageRequest(0, 10, Direction.ASC, "name"));
     * for(HotelSummary summay:hotels){
     * 		System.out.println("Name" +summay.getName());
     * 	}
     * 在运行中 Spring 会给接口（HotelSummary）自动生产一个代理类来接收返回的结果，代码汇总使用 getXX的形式来获取
     *
     */


}
